<!--
  可复用的拖拽组件

  功能特性:
  - 基于 @atlaskit/pragmatic-drag-and-drop 的拖拽功能封装
  - 支持内部拖拽和跨窗口拖拽
  - 支持自定义拖拽数据类型
  - 支持边缘检测和放置位置计算
  - 内置拖拽指示器视觉反馈
  - 提供丰富的插槽和事件
  - 完整的 TypeScript 类型支持

  使用示例:
  <DraggableItem
    drag-type="browser-tab"
    :drag-data="{ data: tab, inGroupId: group?.id }"
    :accepted-types="['browser-tab', 'browser-tab-group']"
    :allowed-edges="['left', 'right']"
    @drop="handleDrop"
  >
    <div class="tab-item">{{ tab.title }}</div>
  </DraggableItem>
-->

<template>
  <div
    ref="containerRef"
    :class="[
      'draggable-item',
      {
        [dragClass ?? '']: dragClass && isDragging,
        [dropClass ?? '']: dropClass && isDropTarget
      }
    ]"
  >
    <!-- 默认插槽：传递拖拽状态给使用者 -->
    <slot
      :closest-edge="closestEdge"
      :drag-state="dragState"
      :drop-state="dropState"
      :is-dragging="isDragging"
      :is-drop-target="isDropTarget"
    />

    <!-- 拖拽指示器 -->
    <DropIndicator
      v-if="showDropIndicator && isDropTarget && closestEdge"
      :color="dropIndicatorColor"
      :edge="closestEdge"
      :offset="dropIndicatorOffset"
    />

    <!-- 拖拽预览插槽 -->
    <Teleport v-if="dragState.type === 'preview'" :to="dragState.container">
      <slot
        v-if="$slots.preview"
        :container="dragState.container"
        :drag-data="resolvedDragData"
        name="preview"
      />
      <div v-else class="draggable-item-preview">
        <slot
          :closest-edge="closestEdge"
          :drag-state="dragState"
          :drop-state="dropState"
          :is-dragging="isDragging"
          :is-drop-target="isDropTarget"
        />
      </div>
    </Teleport>
  </div>
</template>

<script setup lang="ts" generic="T extends DragType">
import { computed, ref, watch } from 'vue'
import type { Edge } from '@atlaskit/pragmatic-drag-and-drop-hitbox/closest-edge'
import type { DragData, DragType } from '@/composables/dragAndDrop/dragDropUtil'
import { useDragHandle } from '@/composables/dragAndDrop/useDragHandle'
import { useDropHandle } from '@/composables/dragAndDrop/useDropHandle'
import DropIndicator from '@/windows/layoutBrowser/components/common/DropIndicator.vue'
import type { DraggableItemEmits, DraggableItemProps } from './DraggableItem.types'

/**
 * 组件 Props 定义
 */
const props = withDefaults(defineProps<DraggableItemProps<T>>(), {
  noDrag: false,
  nativeDrag: false,
  showDropIndicator: true,
  previewOffset: () => ({ x: '0', y: '0' })
})

/**
 * 组件 Emits 定义
 */
const emit = defineEmits<DraggableItemEmits<T>>()

/**
 * 容器元素引用
 */
const containerRef = ref<HTMLElement>()

/**
 * 解析拖拽数据（用于预览插槽）
 */
const resolvedDragData = computed(() => {
  return typeof props.dragData === 'function'
    ? (props.dragData as () => DragData[T])()
    : props.dragData
})

/**
 * 初始化拖拽功能
 * 注意：dragData 可以是静态对象或函数，useDragHandle 会自动处理
 */
const { dragState } = useDragHandle({
  el: containerRef,
  noDrag: props.noDrag,
  nativeDrag: props.nativeDrag,
  dragType: props.dragType,
  dragData: props.dragData,
  previewOffset: props.previewOffset
})

/**
 * 初始化放置功能（仅当提供了 acceptedTypes 时）
 */
const { dropState } = props.acceptedTypes
  ? useDropHandle({
      el: containerRef,
      noDrag: props.noDrag,
      acceptedTypes: props.acceptedTypes,
      allowedEdges: props.allowedEdges,
      canDrop: props.canDrop,
      onDrop: (data, edge, isExternal) => {
        emit('drop', data, edge, isExternal)
      }
    })
  : { dropState: ref({ type: 'idle' as const }) }

/**
 * 计算属性：是否正在拖拽
 */
const isDragging = computed(() => {
  return dragState.value.type === 'dragging' || dragState.value.type === 'preview'
})

/**
 * 计算属性：是否为放置目标
 */
const isDropTarget = computed(() => {
  return dropState.value.type === 'drag-over'
})

/**
 * 计算属性：最近的边缘位置
 */
const closestEdge = computed<Edge | null>(() => {
  return dropState.value.type === 'drag-over' ? dropState.value.closestEdge : null
})

/**
 * 监听拖拽状态变化，触发相应事件
 */
watch(
  () => dragState.value.type,
  (newType, oldType) => {
    if (newType === 'dragging' && oldType !== 'dragging') {
      emit('drag-start')
    } else if (newType === 'idle' && oldType !== 'idle') {
      emit('drag-end')
    }
  }
)

/**
 * 监听放置状态变化，触发相应事件
 */
watch(
  () => dropState.value.type,
  (newType, oldType) => {
    if (newType === 'drag-over' && oldType !== 'drag-over') {
      emit('drag-enter')
    } else if (newType === 'idle' && oldType === 'drag-over') {
      emit('drag-leave')
    }
  }
)

/**
 * 暴露给父组件的属性和方法
 */
defineExpose({
  containerRef,
  dragState,
  dropState,
  isDragging,
  isDropTarget,
  closestEdge
})
</script>

<style scoped>
.draggable-item {
  position: relative;
}

.draggable-item-preview {
  /* 默认预览样式，可以被使用者覆盖 */
  opacity: 0.8;
  pointer-events: none;
}
</style>
